package com.newcoder.community.util;

import org.apache.commons.lang3.CharUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
import java.util.Stack;


@Component
public class SensitiveFilter {
    private static final Logger logger = LoggerFactory.getLogger(SensitiveFilter.class);
    private static final String REPLACEMENT = "***";
    //初始化根节点
    private  TrieNode root = new TrieNode();
    @PostConstruct
    public void init(){
        try(
             InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("sensitive-words.txt");
             BufferedReader reader = new BufferedReader(new InputStreamReader(resourceAsStream));
        ){
            String keyWord;
            while ((keyWord = reader.readLine())!=null){
                //敏感词添加到前缀树
                this.addKeyWord(keyWord);

            }

        }catch (Exception e){
            logger.error("敏感词文件读取失败:"+e.getMessage());
        }

    }
    //将敏感词添加到前缀树
    private void addKeyWord(String keyWord){
        TrieNode tempNode = root;
        for(int i=0;i<keyWord.length();i++){
            char c = keyWord.charAt(i);
            TrieNode subNode= tempNode.getSubNode(c);
            if(subNode==null){
                subNode  =new TrieNode();
                tempNode.addSubNode(c,subNode);
            }
            tempNode = subNode;
            if(i==keyWord.length()-1){
                tempNode.setKeyWordEnd(true);
            }
        }
    }

    /**
     * 过滤敏感词
     * @param text 待过滤的文本
     * @return 过滤后的文本
     */
    public String filter(String text){
        if(text==null){
            return null;
        }
        //指针1
        TrieNode tempNode  = this.root;
        //指针2
        int begin = 0;
        //指针3
        int end = 0;
        StringBuilder stringBuilder = new StringBuilder();
        while (begin<text.length()){
            char c = text.charAt(end);
            TrieNode subNode = tempNode.getSubNode(c);
            if(subNode==null){
                stringBuilder.append(c);
                begin++;
                end=begin;
            }else{
                   while(end<text.length()){
                       c = text.charAt(end);
                       subNode = tempNode.getSubNode(c);
                       if(isSymbol(text.charAt(end))){
                           end++;
                           continue;
                       }
                       if(subNode==null){
                           break;
                       }
                       if(subNode.isKeyWordEnd){
                           stringBuilder.append(REPLACEMENT);
                           begin=end;
                           break;
                       }else{
                           end++;
                           tempNode = subNode;
                       }
                   }
                   if(begin!=end){
                       stringBuilder.append(text.substring(begin,begin+1));
                   }
                   begin++;
                   end=begin;
                   tempNode = this.root;
            }
        }
        return stringBuilder.toString();
    }
    //判断是否为符号
    private boolean isSymbol(Character c){
        //0x2E80~0x9FFF是东亚文字范围
        return !CharUtils.isAsciiAlphanumeric(c)&&(c<0x2E80||c>0x9FFF);

    }
    //前缀树
    private class TrieNode{
        // 关键词结束的标识
        private boolean isKeyWordEnd = false;
        //当前节点的子节点
        private Map<Character,TrieNode> subNodes = new HashMap<>();
        public boolean isKeyWordEnd() {
            return isKeyWordEnd;
        }

        public void setKeyWordEnd(boolean keyWordEnd) {
            isKeyWordEnd = keyWordEnd;
        }
        //添加子节点
        public void addSubNode(Character c,TrieNode value){
            subNodes.put(c,value);
        }
        //获取子节点
        public TrieNode getSubNode(Character c){
            return subNodes.get(c);
        }
    }

}
